﻿using SortingNetworkSimulator.Creators;
using SortingNetworkSimulator.Model;
using SortingNetworkSimulator.View;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SortingNetworkSimulator
{
    public partial class MainWindow : Form
    {
        private const int TesterMaxInputsCount = 63;

        private NetworkDesigner networkDesigner;
        private Network network;

        public MainWindow()
        {
            InitializeComponent();
            this.networkPanel.AutoScroll = true;
            this.networkContainer.SizeMode = PictureBoxSizeMode.AutoSize;
        }

        private void addComparatorButton_Click(object sender, EventArgs e)
        {
            int wireOneIndex, wireTwoIndex, layer;
            try
            {
                if (CheckComparatorParams(out wireOneIndex, out wireTwoIndex, out layer))
                {
                    network.AddComparator(wireOneIndex, wireTwoIndex, layer);
                }
                else
                {
                    ShowComparatorParamsError();
                    return;
                }

                networkDesigner = new NetworkDesigner(networkContainer, networkPanel, network);

                int countTemp = networkContainer.Controls.Count;
                for (int i = 0; network != null && i < networkContainer.Controls.Count; )
                {
                    networkContainer.Controls[i].Dispose();
                }
                networkDesigner.DrawNetwork(network, showLayersCheckbox.Checked);
                networkDesigner.DrawResultBoxes(network.InputsCount);


            }
            catch (NullReferenceException nre)
            {
                MessageBox.Show("To add comparators, at first you need to create network.", "Error", MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
            catch (ArgumentException ae)
            {
                MessageBox.Show(ae.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (InvalidOperationException ioe)
            {
                MessageBox.Show(ioe.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void createNetworkButton_Click(object sender, EventArgs e)
        {
            int inputsCount;

            for (int i = 0; network != null && i < network.InputsCount; i++)
                networkPanel.Controls.RemoveByKey("valueBox" + i.ToString());

            for (int i = 0; network != null && i < networkContainer.Controls.Count; )
                networkContainer.Controls[i].Dispose();

            if (Int32.TryParse(inputsCountTextbox.Text, out inputsCount))
            {
                network = new Network(inputsCount);
            }
            else
            {
                MessageBox.Show("Please enter only numbers.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                inputsCountTextbox.Clear();
                return;
            }
           
            networkDesigner = new NetworkDesigner(networkContainer, networkPanel, network);
            networkDesigner.DrawNetwork(network, showLayersCheckbox.Checked);
            networkDesigner.DrawValueBoxes(inputsCount);
            networkDesigner.DrawResultBoxes(inputsCount);
        }

        private void proccessButton_Click(object sender, EventArgs e)
        {
            int position;
            double value;
            double[] values = new double[network.InputsCount];

            foreach (Control ctrl in this.networkPanel.Controls)
            {
                if (ctrl is TextBox && ctrl.Name.Contains("valueBox"))
                {
                    position = Int32.Parse(ctrl.Name.Substring(8, ctrl.Name.Length - 8));
                    if (Double.TryParse(ctrl.Text, out value))
                    {
                        values[position] = value;
                    }
                    else
                    {
                        MessageBox.Show("Please enter number in entry: " + (position+1).ToString(), 
                            "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        ctrl.Text = "";
                        return;
                    }
                }
            }

            network.Process(values);

            foreach (Control ctrl in this.networkContainer.Controls)
            {                                              
                if (ctrl is TextBox && ctrl.Name.Contains("resultBox"))
                {
                    position = Int32.Parse(ctrl.Name.Substring(9, ctrl.Name.Length - 9));
                    ctrl.Text = values[position].ToString();
                }
            }

        }

        private void openButton_Click(object sender, EventArgs e)
        {
            OpenFileDialog openfile = new OpenFileDialog();
            int position = 0;

            openfile.Filter = "Text Files (.txt)|*.txt|All Files (*.*)|*.*";
            openfile.FilterIndex = 1;
            openfile.Multiselect = false;

            DialogResult userClickedOK = openfile.ShowDialog();

            if (userClickedOK == DialogResult.OK)
            {                
                System.IO.Stream fileStream = File.OpenRead(openfile.FileName);

                using (System.IO.StreamReader reader = new System.IO.StreamReader(fileStream))
                {
                    foreach (Control ctrl in this.networkPanel.Controls)
                        if (ctrl is TextBox && ctrl.Name.Contains("valueBox" + position.ToString()))
                        {
                            ctrl.Text = reader.ReadLine();
                            position++;
                        }
                }
                fileStream.Close();
            }
        }

        private void insertSortButton_Click(object sender, EventArgs e)
        {
            try
            {
                InsertSortNetwork insertSort = new InsertSortNetwork(network.InputsCount);

                for (int i = 0; network != null && i < networkContainer.Controls.Count; )
                {
                    networkContainer.Controls[i].Dispose();
                }

                this.network = insertSort.Transform();
                networkDesigner = new NetworkDesigner(networkContainer, networkPanel, network);
                networkDesigner.DrawNetwork(network, showLayersCheckbox.Checked);
                networkDesigner.DrawResultBoxes(network.InputsCount);
            }
            catch (NullReferenceException nre)
            {
                MessageBox.Show("Before creating sorting networks you need to create empty network.", "Error", MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }

        private void mergeSortButton_Click(object sender, EventArgs e)
        {
            try
            {
                double n = Math.Log(network.InputsCount, 2);
                if (n - Math.Truncate(n) == 0)
                {
                    BitonicSorter bs = new BitonicSorter(new Network(network.InputsCount));

                    for (int i = 0; network != null && i < networkContainer.Controls.Count; )
                    {
                        networkContainer.Controls[i].Dispose();
                    }

                    this.network = bs.Transform();
                    networkDesigner = new NetworkDesigner(networkContainer, networkPanel, network);
                    networkDesigner.DrawNetwork(network, showLayersCheckbox.Checked);
                    networkDesigner.DrawResultBoxes(network.InputsCount);
                }
                else
                {
                    MessageBox.Show("Network size must be a power of two", "Error", MessageBoxButtons.OK,
                       MessageBoxIcon.Error);
                }
            }
            catch (NullReferenceException nre)
            {
                MessageBox.Show("Before creating sorting networks you need to create empty network.", "Error", MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }

        private void removeComparatorButton_Click(object sender, EventArgs e)
        {
            try
            {
                network.RemoveComparator();

                networkDesigner.DrawNetwork(network, showLayersCheckbox.Checked);
            }
            catch (InvalidOperationException ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void ShowComparatorParamsError()
        {
            wireOneIndexTextbox.Clear();
            wireTwoIndexTextbox.Clear();
            layerTextbox.Clear();

            MessageBox.Show("Fields for comparator parameters can contain only numbers.", "Error", MessageBoxButtons.OK,
                MessageBoxIcon.Error);
        }

        private bool CheckComparatorParams(out int wireOneIndex, out int wireTwoIndex, out int layer)
        {
            wireOneIndex = 0;
            wireTwoIndex = 0;
            layer = 0;

            return Int32.TryParse(wireOneIndexTextbox.Text, out wireOneIndex) &&
                    Int32.TryParse(wireTwoIndexTextbox.Text, out wireTwoIndex) &&
                    Int32.TryParse(layerTextbox.Text, out layer);
        }

        private void isSortingButton_Click(object sender, EventArgs e)
        {
            if (network.InputsCount <= TesterMaxInputsCount)
            {
                SortingTester tester = new SortingTester(network);

                if (tester.IsSortingNetwork())
                {
                    MessageBox.Show("Network is a sorting network", "Result", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else
                {
                    MessageBox.Show("Network is not a sorting network", "Result", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            else
            {
                MessageBox.Show("Tested network inputs count can not be greater than 63", "Error", MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }

        private void showLayersCheckbox_CheckedChanged(object sender, EventArgs e)
        {
            if (network != null)
            {
                networkDesigner.DrawNetwork(network, showLayersCheckbox.Checked);
            }
        }
    }
}
